import 'package:bigegg/data/repository/xmm_remote_repository.dart';
import 'package:bigegg/entity/im/xmm_im_message.dart';
import 'package:bigegg/entity/user/xmm_wall_user.dart';
import 'package:bigegg/global/im/xmm_im_manager.dart';
import 'package:bigegg/global/user/xmm_account_manager.dart';
import 'package:bigegg/utils/audio/xmm_audio_player.dart';
import 'package:bigegg/utils/audio/xmm_audio_recorder.dart';
import 'package:get/get.dart';
import 'package:rongcloud_im_wrapper_plugin/rongcloud_im_wrapper_plugin.dart';

import '../../../../common/get/controller/xmm_base_controller.dart';
import '../../../common/log/xmm_logcat.dart';
import '../../../global/xmm_app_const.dart';
import '../../../utils/xmm_event_bus.dart';

class XmmChatController extends XmmBaseGetxController {
  final repository = XmmRemoteRepository();

  final isInit = false.obs;

  bool isFirstGetHistoryMessages = true;

  final conversationType = RCIMIWConversationType.private;

  final messageList = <XmmImMessageWarp>[].obs;

  XmmWallUser? userInfo;

  final isRecording = false.obs;

  final isCanSendAudio = false.obs;

  XmmAudioRecorder? audioRecord;

  XmmAudioPlayer? audioPlayer;

  @override
  void onReady() {
    super.onReady();
    XmmEventBus.instance.on(XmmAppConst.eventReceivedMessageKey, (message) {
      insertOrUpdateMessage(message);
      syncReadReceipt(message);
    });
    XmmEventBus.instance.on(XmmAppConst.eventSendMessageKey, (message) {
      insertOrUpdateMessage(message);
    });
    XmmEventBus.instance.on(XmmAppConst.eventSyncMessageStatusKey, (message) {
      insertOrUpdateMessage(message, updateCallback : (messageWarp){
        messageWarp.messageStatus.value = messageWarp.message.sentStatus ?? RCIMIWSentStatus.sent;
      });
    });
  }

  @override
  void onClose() {
    XmmEventBus.instance.off(XmmAppConst.eventReceivedMessageKey);
    XmmEventBus.instance.off(XmmAppConst.eventSendMessageKey);
    audioRecord?.dispose();
    audioPlayer?.release();
    super.onClose();
  }

  void syncReadReceipt(RCIMIWMessage message) {
    XmmImManager.instance.engine?.sendPrivateReadReceiptMessage(
      message.targetId ?? "",
      null,
      message.sentTime ?? 0,
    );
  }

  void insertOrUpdateMessage(RCIMIWMessage message, {Function(XmmImMessageWarp messageWarp)? updateCallback}) {
    int index = -1;
    for (int i = 0; i < messageList.length; i++) {
      XmmImMessageWarp msg = messageList.elementAt(i);
      if (msg.message.messageId == message.messageId) {
        index = i;
        msg.message = message;
        break;
      }
    }
    if (index >= 0) {
      if(updateCallback != null){
        updateCallback.call(messageList.elementAt(index));
      } else {
        messageList.refresh();
      }
    } else {
      messageList.insert(0, XmmImMessageWarp(message));
    }
  }

  Future<void> getUserInfo(userId) async {
    var user = XmmAccountManager.instance.findWallUser(userId);
    if (user.userId != userId) {
      user = await repository.getUserInfo(userId);
      XmmAccountManager.instance.addWallUser(user);
    }
    userInfo = user;
    isInit.value = true;
  }

  Future<void> loadHistoryMessage(String targetId, {int? sentTime}) async {
    IRCIMIWGetMessagesCallback? callback = IRCIMIWGetMessagesCallback(
      onSuccess: (List<RCIMIWMessage>? list) {
        if (list?.isNotEmpty == true) {
          var newList = list?.map((e) => XmmImMessageWarp(e));
          messageList.addAll(newList!);
          if (isFirstGetHistoryMessages) {
            try {
              var message = messageList.firstWhere((element) =>
                  element.message.direction == RCIMIWMessageDirection.receive);
              syncReadReceipt(message.message);
            } catch (e) {
              e.printError();
            }
          }
          isFirstGetHistoryMessages = false;
        }
      },
      onError: (int? code) {
        XmmXLogcat.e("Im loadHistoryMessage result=$code targetId=$targetId sentTime=$sentTime");
      },
    );
    var result = await XmmImManager.instance.engine?.getMessages(
      conversationType,
      targetId,
      null,
      sentTime ?? DateTime.now().millisecondsSinceEpoch,
      RCIMIWTimeOrder.before,
      RCIMIWMessageOperationPolicy.localRemote,
      20,
      callback: callback,
    );
    XmmXLogcat.d("Im loadHistoryMessage result=$result targetId=$targetId sentTime=$sentTime");
  }

  void loadMoreHistoryMessage(String targetId) async {
    await loadHistoryMessage(targetId,
        sentTime: messageList.last.message.sentTime);
  }

  Future<void> sendTextMessage(String text, String targetId,
      {RCIMIWSendMessageCallback? callback}) async {
    var message = await XmmImManager.instance.engine?.createTextMessage(
      conversationType,
      targetId,
      null,
      text,
    );
    sendMessage(message, callback: callback);
  }

  Future<void> sendImageMessage(String path, String targetId,
      {RCIMIWSendMediaMessageListener? callback}) async {
    var message = await XmmImManager.instance.engine?.createImageMessage(
      conversationType,
      targetId,
      null,
      path,
    );
    sendMediaMessage(message, callback: callback);
  }

  Future<void> sendVoiceMessage(String path, String targetId, int duration,
      {RCIMIWSendMediaMessageListener? callback}) async {
    var message = await XmmImManager.instance.engine?.createVoiceMessage(
      conversationType,
      targetId,
      null,
      path,
      duration,
    );
    sendMediaMessage(message, callback: callback);
  }

  Future<void> sendFileMessage(String path, String targetId,
      {RCIMIWSendMediaMessageListener? callback}) async {
    var message = await XmmImManager.instance.engine?.createFileMessage(
      conversationType,
      targetId,
      null,
      path,
    );
    sendMediaMessage(message, callback: callback);
  }

  Future<void> sendMessage(RCIMIWMessage? message,
      {RCIMIWSendMessageCallback? callback}) async {
    if (message == null) {
      XmmXLogcat.e("send message failed");
      return;
    }
    await XmmImManager.instance.sendMessage(message, callback: callback);
  }

  Future<void> sendMediaMessage(RCIMIWMediaMessage? message,
      {RCIMIWSendMediaMessageListener? callback}) async {
    if (message == null) {
      XmmXLogcat.e("send sendMediaMessage failed");
      return;
    }
    await XmmImManager.instance.sendMediaMessage(message, callback: callback);
  }

  void startRecord() {
    audioRecord ??= XmmAudioRecorder(finished: (String path, int duration) {
      XmmXLogcat.d("sendVoiceMessage path=$path, duration=$duration");
      sendVoiceMessage(path, userInfo?.userId ?? "", duration);
    });
    audioRecord?.startRecorder();
  }

  void stopRecord() {
    audioRecord?.stopRecorder();
  }

  void cancelRecord() {
    audioRecord?.cancelRecord();
  }

  void startPlayAudio(
    String path, {
    Function()? onFinished,
    Function(Duration duration, Duration position)? onProgress,
  }) {
    audioPlayer ??= XmmAudioPlayer();
    audioPlayer?.startPlayer(
      path,
      onFinished: onFinished,
      onProgress: onProgress,
    );
  }

  void stopPlayAudio() {
    audioPlayer?.stopPlayer();
  }
}
